use std::i64;
use crate::common::packages::Role;

/**
    数字与字节流相互转化函数
*/

const ERR_TO_SMALL: &str = "input slice too small";

pub fn u32_to_bytes(x: u32) -> [u8; 4] {
    let mut result = [0u8; 4];
    result[0] = ((x >> 24) & 0xFF) as u8;
    result[1] = ((x >> 16) & 0xFF) as u8;
    result[2] = ((x >> 8) & 0xFF) as u8;
    result[3] = (x & 0xFF) as u8;
    result
}

pub fn bytes_to_u32(bytes: &[u8]) -> u32 {
    if bytes.len() < 4 {
        panic!("{}", ERR_TO_SMALL);
    }
    ((bytes[0] as u32) << 24)
        + ((bytes[1] as u32) << 16)
        + ((bytes[2] as u32) << 8)
        + (bytes[3] as u32)
}

pub fn u16_to_bytes(x: u16) -> [u8; 2] {
    let mut result = [0u8; 2];
    result[0] = ((x >> 8) & 0xFF) as u8;
    result[1] = (x & 0xFF) as u8;
    result
}

pub fn bytes_to_u16(bytes: &[u8]) -> u16 {
    if bytes.len() < 2 {
        panic!("{}", ERR_TO_SMALL)
    }
    ((bytes[0] as u16) << 8) + (bytes[1] as u16)
}

pub fn i32_to_bytes(x: i32) -> [u8; 4] {
    if x >= 0 {
        u32_to_bytes(x as u32)
    } else {
        let mut result = u32_to_bytes((-x) as u32);
        result[0] |= 0x01 << 7;
        result
    }
}

pub fn bytes_to_i32(bytes: &[u8]) -> i32 {
    // op 为 true表示为正数
    let op = (bytes[0] & (1u8 << 7)) == 0;
    if op {
        bytes_to_u32(bytes) as i32
    } else {
        let mask = !(1u8 << 7);
        let mut bytes_copy = bytes[0..4].to_vec();
        bytes_copy[0] &= mask;
        -(bytes_to_u32(&bytes_copy) as i32)
    }
}

pub fn u128_to_bytes(x: u128) -> [u8; 16] {
    let mut result = [0u8; 16];
    for i in 0..16 {
        result[i] = ((x >> ((15 - i) * 8)) & 0xFF) as u8;
    }
    result
}

pub fn bytes_to_u128(bytes: &[u8]) -> u128 {
    if bytes.len() < 16 {
        panic!("{}", ERR_TO_SMALL);
    }
    let mut result = 0u128;
    for i in 0..16 {
        result |= (bytes[i] as u128) << ((15 - i) * 8);
    }
    result
}

pub fn bytes_to_u64(bytes: &[u8]) -> u64 {
    if bytes.len() < 8 {
        panic!("{}", ERR_TO_SMALL);
    }
    let mut result = 0u64;
    for i in 0..8 {
        result |= (bytes[i] as u64) << ((7 - i) * 8);
    }
    result
}

pub fn u64_to_bytes(x: u64) -> [u8; 8] {
    let mut result = [0u8; 8];
    for i in 0..8 {
        result[i] = ((x >> ((7 - i) * 8)) & 0xFF) as u8;
    }
    result
}

pub fn i64_to_bytes(x: i64) -> [u8; 8] {
    if x >= 0 {
        u64_to_bytes(x as u64)
    } else {
        let mut result = u64_to_bytes(-x as u64);
        result[0] |= 0x01 << 7;
        result
    }
}

pub fn bytes_to_i64(bytes: &[u8]) -> i64 {
    if bytes.len() < 8 {
        panic!("{}", ERR_TO_SMALL)
    }
    if bytes[0] > (!(1u8 << 7)) {
        // 负数
        let mut result = 0u64;
        let mask = !(1u8 << 7);
        result |= (((bytes[0] & mask) as u64) << 56);
        for i in 1..8 {
            result |= (bytes[i] as u64) << ((7 - i) * 8);
        }
        -(result as i64)
    } else {
        bytes_to_u64(bytes) as i64
    }
}

#[test]
fn test_i64() {
    let mut m:i64 = 99999;
    let a = i64_to_bytes(m);
    assert_eq!(m, bytes_to_i64(&a));
    m = -m;
    let a = i64_to_bytes(m);
    assert_eq!(m, bytes_to_i64(&a));
}

#[test]
fn test_u128() {
    let a = u128_to_bytes(u128::MAX);
    assert_eq!(u128::MAX, bytes_to_u128(&a));
}

#[test]
fn test_i32_to_bytes() {
    let b = i32_to_bytes(1000);
    assert_eq!(1000, bytes_to_i32(&b));
    println!("{:?}", b);
    let b = i32_to_bytes(-1000);
    assert_eq!(-1000, bytes_to_i32(&b));
    println!("{:?}", b);
}

#[test]
fn test_u32_to_bytes() {
    let b = u32_to_bytes(1000);
    assert_eq!(1000, bytes_to_u32(&b));
    println!("{:?}", b);
    let a: u32 = 9980;
    assert_eq!(a, bytes_to_u32(&a.to_be_bytes()))
}
